import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Deque;
import java.util.LinkedList;
import java.util.Scanner;

public class Solution {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        while (sc.hasNext()) {
            int a = sc.nextInt();
            int b = sc.nextInt();
            sc.nextLine();
            String[] s = sc.nextLine().trim().split(" ");
            int[][] nums = new int[a][b];
            for (int i = 0, k = 0; i < a; i++) {
                for (int j = 0; j < b; j++) {
                    nums[i][j] = Integer.parseInt(s[k++]);
                }
            }

            System.out.println(uniquePathsIII(nums));
        }
    }
    
    private static int[][] gid;
    private static boolean[][] used;
    private static Deque<int[]> stack;
    private static int res;
    private static int len1;
    private static int len2;
    private static int count0;

    public static int uniquePathsIII(int[][] grid) {
        len1 = grid.length;
        if (len1 == 0) return 0;
        len2 = grid[0].length;
        if (len2 == 0) return 0;
        stack = new LinkedList<>();
        used = new boolean[len1][len2];

        count0 = getElemCount(grid, 0);

        res = 0;
        int i = 0, j = 0;
        ii:for (; i < len1; i++) {
            for (; j < len2; j++) {
                if (grid[i][j] == 1) {

                    break ii;
                }
            }
        }
        dfs(grid, i+1, j);
        dfs(grid, i-1, j);
        dfs(grid, i, j-1);
        dfs(grid,i , j+1);
        return res;

    }

    public static void dfs(int[][] arr, int i, int j ) {
        if (i < 0 || i >= len1 || j < 0 || j >= len2) {
            return;
        }
        if (stack.size() == count0 && arr[i][j] == 2) {
            res ++;
            return;
        }
        if (arr[i][j] == 2 || arr[i][j] == 1 || used[i][j] || arr[i][j] == -1) {
            return;
        }

        used[i][j] = true;
        stack.push(new int[]{i, j});
        dfs(arr, i+1, j);
        dfs(arr, i-1, j);
        dfs(arr, i, j-1);
        dfs(arr,i , j+1);
        int[] tmp = stack.pop();
        used[i][j] = false;



    }

    public static int getElemCount(int [][] arr, int value) {
        int ans = 0;
        for (int[] nums: arr) {
            for (int a :
                    nums) {
                if (a == value) {
                    ans++;
                }
            }
            
        }
        return ans;
    } 
}


/*回溯法总结：
* 1.需要的全局变量（或者说是需要在dfs内参数传入的变量）：used，待处理数组arr，结果res，可选（数组长度：可以在函数内求，path栈：需要记录回溯的路径时候使用
* 2.单独需要在dfs里面传入的参数：当前节点下移标志，比如depth，以及当前节点坐标
* 3. dfs结构：递归出口 +if判断剪枝（具体位置不定，根据题选择）+ for循环可选分支{占用used+（入path栈）+递归调用+（出path栈）释放used*/


/*规范修改后的dfs*/
class Solution2 {

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        while (sc.hasNext()) {
            int a = sc.nextInt();
            int b = sc.nextInt();
            sc.nextLine();
            String[] s = sc.nextLine().trim().split(" ");
            int[][] nums = new int[a][b];
            for (int i = 0, k = 0; i < a; i++) {
                for (int j = 0; j < b; j++) {
                    nums[i][j] = Integer.parseInt(s[k++]);
                }
            }

            System.out.println(uniquePathsIII(nums));
        }
    }

    // 一定需要添加的全局变量
    private static int[][] arr;
    private static boolean[][] used;
    private static int res;

    // 根据需要添加的变量
    private static int len1;
    private static int len2;
    private static int depth;
    private static int[][] pos;
    private static int count0;

    public static int uniquePathsIII(int[][] grid) {

        arr = grid;
        len1 = arr.length;
        len2 = arr[0].length;
        count0 = 0;
        int i0 = 0, j0 = 0;
        pos = new int[][]{{1, 0}, {-1, 0}, {0, -1}, {0, 1}};
        depth = 0;
        used = new boolean[len1][len2];

        for (int i = 0; i < len1; i++) {
            for (int j = 0; j < len2; j++) {
                if (arr[i][j] == 0) {
                    count0++;
                }
                if (arr[i][j] == 1) {
                    i0 = i;
                    j0 = j;
                }
            }
        }
        dfs(i0-1, j0);
        dfs(i0+1, j0);
        dfs(i0, j0-1);
        dfs(i0, j0+1);
        return res;

    }

    public static void dfs(int i, int j) {

        // 需要递归的条件
        if (i >= 0 && i < len1 && j >= 0 && j < len2) {
            // di gui chu kou
            if (depth == count0 && arr[i][j] == 2) {
                res ++;
                return;
            }
            for (int k = 0; k < 4; k++) {
                if (arr[i][j] == 0 && !used[i][j]) {
                    used[i][j] = true;
                    depth ++;
                    dfs(i+pos[k][0], j+pos[k][1]);
                    depth --;
                    used[i][j] = false;
                }
            }
        }
    }
}